#include <buola/gui/x11/icccm.h>

#include <buola/gui/x11/cx11toolkit.h>
#include <buola/gui/x11/cx11display.h>

#include <X11/Xatom.h>

#include <buola/gui/x11/cpixmap.h>
#include <X11/Xutil.h>
#include <buola/image/cpicture.h>

namespace buola { namespace gui { namespace x11 { namespace icccm {

/////////////////////////////////////// read functionality ///////////////////////////////////////

/////////////////////////////
// ICCCM client properties
//

std::wstring read_wm_name(Window pID,CX11Display *pDisplay)
{
    std::wstring lResult;
    pDisplay->GetWindowProperty(pID,XA_WM_NAME,XA_STRING,lResult);
    return lResult;
}

std::string read_wm_class(Window pID,CX11Display *pDisplay)
{
    std::string lResult;
    pDisplay->GetWindowProperty(pID,XA_WM_CLASS,XA_STRING,lResult);
    return lResult;
}

std::string read_wm_client_machine(Window pID,CX11Display *pDisplay)
{
    std::string lResult;
    pDisplay->GetWindowProperty(pID,XA_WM_CLIENT_MACHINE,XA_STRING,lResult);
    return lResult;
}

bool read_wm_normal_hints(Window pID,CSizeHints &pHints,CX11Display *pDisplay)
{
    //set some sane defaults
    pHints.mFlags=SIZEHINT_NONE;
    pHints.mBase={-1,-1};
    pHints.mMin={-1,-1};
    pHints.mMax={-1,-1};
    pHints.mInc={1,1};

    XSizeHints lHints;
    long lMSize;
    if(!XGetWMNormalHints(pDisplay->GetDisplay(),pID,&lHints,&lMSize))
    {
        msg_warn() << "Can't get wm normal hints\n";
        return false;
    }

    if(lHints.flags&USPosition)
    {
        pHints.mFlags|=HINT_USERPOS;
    }

    if(lHints.flags&PPosition)
    {
        pHints.mFlags|=HINT_PROGRAMPOS;
    }

    if(lHints.flags&USSize)
    {
        pHints.mFlags|=HINT_USERSIZE;
    }

    if(lHints.flags&PSize)
    {
        pHints.mFlags|=HINT_PROGRAMSIZE;
    }

    //check for fixed size
    if ((lHints.flags&(PMinSize|PMaxSize))==(PMinSize|PMaxSize))
    {
        if(lHints.min_width==lHints.max_width&&
            lHints.min_height==lHints.max_height)
        {
            pHints.mFlags|=HINT_FIXED;
        }
    }

    if(lHints.flags&PBaseSize)
    {
        pHints.mFlags|=HINT_BASE;
        pHints.mBase={lHints.base_width,lHints.base_height};
    }

    if(lHints.flags&PMinSize)
    {
        pHints.mFlags|=HINT_MIN;
        pHints.mMin={lHints.min_width,lHints.min_height};
    }

    if(lHints.flags&PMaxSize)
    {
        pHints.mFlags|=HINT_MAX;
        pHints.mMax={lHints.max_width,lHints.max_height};
    }

    if(lHints.flags&PResizeInc)
    {
        pHints.mFlags|=HINT_RESIZE;
        pHints.mInc={lHints.width_inc,lHints.height_inc};
    }

    return true;
}

bool read_wm_hints(Window pID,CWMHints &pHints,CX11Display *pDisplay)
{
    //set some sane defaults
    pHints.mFlags=HINT_WANTSFOCUS;
    pHints.mIconPixmap=0;
    pHints.mIconMask=0;
    pHints.mGroupLeader=0;

    XWMHints *lHints=XGetWMHints(pDisplay->GetDisplay(),pID);

    if(!lHints)
    {
        msg_warn() << "Can't get WM hints\n";
        return false;
    }

    if((lHints->flags&InputHint)&&!lHints->input)
        pHints.mFlags&=~HINT_WANTSFOCUS;

    if(lHints->flags&IconPixmapHint)
        pHints.mIconPixmap=lHints->icon_pixmap;
    if(lHints->flags&IconMaskHint)
        pHints.mIconMask=lHints->icon_mask;
    if(lHints->flags&WindowGroupHint)
        pHints.mGroupLeader=lHints->window_group;
    if(lHints->flags&XUrgencyHint)
        pHints.mFlags|=HINT_URGENCY;

    XFree(lHints);

    return true;
}

Window read_wm_transient_for(Window pID,CX11Display *pDisplay)
{
    Window lWindow;
    if(!XGetTransientForHint(pDisplay->GetDisplay(),pID,&lWindow))
        return None;

    return lWindow;
}

EWMProtocols read_wm_protocols(Window pID,CX11Display *pDisplay)
{
    Atom *lProtocols;
    int lCount;

    EWMProtocols lResult=PROTOCOL_NONE;

    if(XGetWMProtocols(pDisplay->GetDisplay(),pID,&lProtocols,&lCount)==0)
    {
        return PROTOCOL_NONE;
    }

    for (int i = 0; i < lCount; i++)
    {
        if(lProtocols[i]==pDisplay->Atoms().mDeleteWindow)
        {
            lResult|=PROTOCOL_DELETE;
        }
        else if(lProtocols[i]==pDisplay->Atoms().mTakeFocus)
        {
            lResult|=PROTOCOL_TAKEFOCUS;
        }
        else if(lProtocols[i]==pDisplay->Atoms().mNetWMSyncRequest)
        {
            lResult|=PROTOCOL_SYNCREQUEST;
        }
    }

    XFree(lProtocols);

    return lResult;
}

EWMState read_wm_state(Window pID,CX11Display *pDisplay)
{
    int *lProp;
    int **lPProp=&lProp;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mState,pDisplay->Atoms().mState,(void**)lPProp,1);

    if(lCount<=0)
        return WMSTATE_NORMAL;

    EWMState lResult=WMSTATE_NORMAL;
    
    if(*lProp==WithdrawnState)
        lResult=WMSTATE_WITHDRAWN;
    else if(*lProp==IconicState)
        lResult=WMSTATE_ICONIC;

    XFree(lProp);
    
    return lResult;
}

/////////////////////////////
// motif client properties
//

bool read_motif_hints(Window pID,CMotifHints &pHints,CX11Display *pDisplay)
{
    CMotifHints *lHints;
    CMotifHints **lPHints=&lHints;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mMotifHints,pDisplay->Atoms().mMotifHints,
                                           (void**)lPHints,100);

    if(lCount!=5)
    {
        pHints.mFlags=0;
        return false;
    }
    else
    {
        pHints=*lHints;
        XFree(lHints);
        return true;
    }
}

///////////////////////////
// NET client properties
//

std::wstring read_net_wm_name(Window pID,CX11Display *pDisplay)
{
    std::wstring lResult;
    pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMName,pDisplay->Atoms().mUTF8,lResult);
    return lResult;
}

bool read_net_wm_desktop(Window pID,unsigned int &pValue,CX11Display *pDisplay)
{
    int lDesktop;

    if(!pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMDesktop,&lDesktop))
    {
        pValue=0;
        return false;
    }

    if(lDesktop<0||lDesktop>1000)
    {
        pValue=0xffffffff;
    }
    else
    {
        pValue=lDesktop;
    }

    return true;
}

ENetState read_net_wm_state(Window pID,CX11Display *pDisplay)
{
    ENetState lResult=NETSTATE_NONE;

    Atom *lAtoms;
    Atom **lPAtoms=&lAtoms;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMState,XA_ATOM,(void**)lPAtoms,100);

    if(lCount<0)
    {
        msg_warn() << "Can't get NETState\n";
        return lResult;
    }

    for(int i=0;i<lCount;i++)
    {
        if(lAtoms[i]==pDisplay->Atoms().mNetWMStateSticky)
        {
            lResult|=NETSTATE_STICKY;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMStateAbove)
        {
            lResult|=NETSTATE_ABOVE;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMStateBelow)
        {
            lResult|=NETSTATE_BELOW;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMStateSkipTaskbar)
        {
            lResult|=NETSTATE_SKIPTASKBAR;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMStateSkipPager)
        {
            lResult|=NETSTATE_SKIPPAGER;
        }
        else
        {
            msg_debug<5>() << pDisplay->GetAtomName(lAtoms[i]) << "\n";
        }
    }

    if(lAtoms)
        XFree(lAtoms);

    return lResult;
}

EWindowType read_net_wm_window_type(Window pID,CX11Display *pDisplay)
{
    EWindowType lResult=EWindowType::NORMAL;

    Atom *lAtoms;
    Atom **lPAtoms=&lAtoms;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMWindowType,XA_ATOM,(void**)lPAtoms,100);

    if(lCount<0)
    {
        msg_warn() << "Can't get NETWindowType\n";
        return lResult;
    }

    for(int i=0;i<lCount;i++)
    {
        if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeDesktop)
        {
            lResult=EWindowType::DESKTOP;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeDock)
        {
            lResult=EWindowType::DOCK;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeToolbar)
        {
            lResult=EWindowType::TOOLBAR;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeMenu)
        {
            lResult=EWindowType::MENU;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeUtility)
        {
            lResult=EWindowType::UTILITY;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeSplash)
        {
            lResult=EWindowType::SPLASH;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeDialog)
        {
            lResult=EWindowType::DIALOG;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeDropdownMenu)
        {
            lResult=EWindowType::DROPDOWNMENU;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypePopupMenu)
        {
            lResult=EWindowType::POPUPMENU;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeTooltip)
        {
            lResult=EWindowType::TOOLTIP;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeNotification)
        {
            lResult=EWindowType::NOTIFICATION;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeCombo)
        {
            lResult=EWindowType::COMBO;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeDND)
        {
            lResult=EWindowType::DND;
            break;
        }
        else if(lAtoms[i]==pDisplay->Atoms().mNetWMWindowTypeNormal)
        {
            lResult=EWindowType::NORMAL;
            break;
        }
        else
        {
            msg_warn() << "Unknown window type " << pDisplay->GetAtomName(lAtoms[i]) << "\n";
        }
    }

    if(lAtoms)
        XFree(lAtoms);

    return lResult;
}

CRect_i read_net_wm_strut(Window pID,CX11Display *pDisplay)
{
    CRect_i lResult(0,0,0,0);

    long int *lStrut;
    long int **lPStrut=&lStrut;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMStrut,XA_CARDINAL,(void**)lPStrut,4);

    if(lCount<4)
        return lResult;

    lResult.l=lStrut[0];
    lResult.r=lStrut[1];
    lResult.t=lStrut[2];
    lResult.b=lStrut[3];

    XFree(lStrut);

    return lResult;
}

CRect_i read_net_wm_icon_geometry(Window pID,CX11Display *pDisplay)
{
    CRect_i lResult(nUndefined);

    long int *lGeometry;
    long int **lPGeometry=&lGeometry;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMIconGeometry,XA_CARDINAL,(void**)lPGeometry,4);

    if(lCount<4)
        return lResult;

    lResult.l=lGeometry[0]+1;
    lResult.t=lGeometry[1]+1;
    lResult.r=lGeometry[0]+lGeometry[2]-2;
    lResult.b=lGeometry[1]+lGeometry[3]-2;

    XFree(lGeometry);

    return lResult;
}

bool read_net_wm_icon(Window pID,std::vector<img::CPicture> &pIcons,CX11Display *pDisplay)
{
    pIcons.clear();

    unsigned long int *lRaw;
    unsigned long int **lPRaw=&lRaw;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMIcon,XA_CARDINAL,(void**)lPRaw,40000);

    if(lCount<=0)
    {
        lCount=0;
    }
    else if(lCount<2)
    {
        XFree(lRaw);
        lCount=0;
    }

    int lPos=0;

    while(lPos<lCount)
    {
        CSize_i lSize(lRaw[lPos+0],lRaw[lPos+1]);

        if(lCount<lPos+lSize.x*lSize.y+2)
        {
            msg_warn() << "Short icon object!!\n";
            break;
        }

        unsigned int *lIRaw=alloc_array<unsigned int>(lSize.x*lSize.y);

        for(int i=0;i<lSize.x*lSize.y;i++)
        {
            lIRaw[i]=lRaw[lPos+2+i];
        }

        img::CPicture lWMIcon(clone(img::view_rgba8((unsigned char*)lIRaw,CSize_i(lSize))));
        pIcons.push_back(lWMIcon);

        lPos+=(int)lSize.x*(int)lSize.y+2;
    }

    if(lCount)
        XFree(lRaw);

    if(!pIcons.size())
    {
        XWMHints *lHints=XGetWMHints(pDisplay->GetDisplay(),pID);
    
        if(lHints)
        {
            if(lHints->flags&IconPixmapHint)
            {
                CPixmap *lIconPixmap=new CPixmap;
                if(lIconPixmap->Create(lHints->icon_pixmap))
                {
                    CPixmap *lMaskPixmap=nullptr;
                
                    if(lHints->flags&IconMaskHint)
                    {
                        lMaskPixmap=new CPixmap;
                        if(!lMaskPixmap->Create(lHints->icon_mask))
                        {
                            delete lMaskPixmap;
                            lMaskPixmap=nullptr;
                        }
                    }

                    //img::CPicture lImage;
                    //TODO_URGENT:lTBIcon.mImage->Create(lIconPixmap,lMaskPixmap,lIconPixmap->GetSurfaceSize());
                }
                else
                {
                    delete lIconPixmap;
                }
            }
        
            XFree(lHints);
        }
    }
    
    return pIcons.size();
}

static const unsigned int sMaxOpacity=0xffffffff;

double read_net_wm_window_opacity(Window pID,CX11Display *pDisplay)
{
    unsigned int *lOpacity;
    unsigned int **lPOpacity=&lOpacity;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWMWindowOpacity,XA_CARDINAL,(void**)lPOpacity,1);

    if(lCount==1) //ok
    {
        double lResult=double(*lOpacity)/double(sMaxOpacity);
        XFree(lOpacity);
        return lResult;
    }
    else
    {
        return 1.0;
    }
}

///////////////////////////
// NET root properties
//

bool read_net_client_list_stacking(std::vector<Window> &pList,CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    pList.clear();

    Window *lList;
    Window **lPList=&lList;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetClientListStacking,XA_WINDOW,(void**)lPList,1000);

    if(lCount<0)
        return false;

    pList.resize(lCount);
    
    for(int i=0;i<lCount;i++)
    {
        pList[i]=lList[i];
    }

    XFree(lList);

    return true;
}

Window read_net_active_window(CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    Window *lWindow;
    Window **lPWindow=&lWindow;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetActiveWindow,XA_WINDOW,(void**)lPWindow,1);

    if(lCount<=0) return None;

    Window lResult=*lWindow;
    XFree(lWindow);
    return lResult;
}

int read_net_number_of_desktops(CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    int *lReturn;
    int **lPReturn=&lReturn;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetNumberOfDesktops,XA_CARDINAL,(void**)lPReturn,1);

    if(lCount<=0)
        return 0;

    int lResult=*lReturn;
    XFree(lReturn);
    return lResult;
}

int read_net_current_desktop(CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    int *lReturn;
    int **lPReturn=&lReturn;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetCurrentDesktop,XA_CARDINAL,(void**)lPReturn,1);
    
    if(lCount<=0)
        return -1;

    int lResult=*lReturn;
    XFree(lReturn);
    return lResult;
}

CSize_i read_net_desktop_geometry(CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    int *lReturn;
    int **lPReturn=&lReturn;
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetDesktopGeometry,XA_CARDINAL,(void**)lPReturn,2);
    
    if(lCount<=2)
        return CSize_i(nUndefined);

    CSize_i lResult(lReturn[0],lReturn[1]);
    XFree(lReturn);
    return lResult;
}

bool read_net_desktop_viewport(std::vector<CPoint_i> &pViewports,CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    int *lViewPort;
    int **lPViewPort=&lViewPort;

    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetDesktopViewport,
                        XA_CARDINAL,(void**)lPViewPort,100);
    if(lCount<=0)
    {
        pViewports.clear();
        return false;
    }

    pViewports.resize(lCount/2);

    for(int i=0;i<lCount/2;i++)
    {
        pViewports[i]={lViewPort[i*2],lViewPort[i*2+1]};
    }

    XFree(lViewPort);

    return true;
}

bool read_net_workarea(std::vector<CRect_i> &pWorkAreas,CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();

    int *lWorkArea;
    int **lPWorkArea=&lWorkArea;
    
    int lCount=pDisplay->GetWindowProperty(pID,pDisplay->Atoms().mNetWorkArea,
                        XA_CARDINAL,(void**)lPWorkArea,100);

    if(lCount<=0)
    {
        pWorkAreas.clear();
        return false;
    }

    pWorkAreas.resize(lCount/4);

    for(int i=0;i<lCount/4;i++)
    {
        pWorkAreas[i]={CPoint_i(lWorkArea[i*4],lWorkArea[i*4+1]),
                           CSize_i(lWorkArea[i*4+2],lWorkArea[i*4+3])};
    }

    XFree(lWorkArea);

    return true;
}

/////////////////////////////////////// write functionality ///////////////////////////////////////

/////////////////////////////
// ICCCM client properties
//

void write_wm_state(Window pID,EWMState pState,CX11Display *pDisplay)
{
    int lProp;

    if(pState==WMSTATE_WITHDRAWN)
    {
        lProp=WithdrawnState;
    }
    else if(pState==WMSTATE_ICONIC)
    {
        lProp=IconicState;
    }
    else
    {
        lProp=NormalState;
    }

    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mState,pDisplay->Atoms().mState,32,1,&lProp);
}

void write_wm_protocols(Window pID,EWMProtocols pProtocols,CX11Display *pDisplay)
{
    Atom lAtoms[10];

    int lNum=0;

    if(pProtocols&PROTOCOL_DELETE)
        lAtoms[lNum++]=pDisplay->Atoms().mDeleteWindow;
    if(pProtocols&PROTOCOL_TAKEFOCUS)
        lAtoms[lNum++]=pDisplay->Atoms().mTakeFocus;
    if(pProtocols&PROTOCOL_CONTEXTHELP)
        lAtoms[lNum++]=pDisplay->Atoms().mContextHelp;
    if(pProtocols&PROTOCOL_SYNCREQUEST)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMSyncRequest;
    
    XSetWMProtocols(pDisplay->GetDisplay(),pID,lAtoms,lNum);

    pDisplay->SetWindowPropertyAsAtom(pID,pDisplay->Atoms().mDndAware,3);
}

void write_wm_command(Window pID,const std::string &pCommand,CX11Display *pDisplay)
{
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mWMCommand,XA_STRING,pCommand);
}
    
void write_wm_client_machine(Window pID,const std::string &pHost,CX11Display *pDisplay)
{
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mWMClientMachine,XA_STRING,pHost);
}

void write_wm_class(Window pID,const std::string &pClass,const std::string &pSubClass,CX11Display *pDisplay)
{
    unsigned char lFinal[pClass.length()+pSubClass.length()+2];
    
    int i;
    
    for(i=0;i<pClass.length();i++)
    {
        lFinal[i]=pClass[i];
    }
    lFinal[i++]='\0';
    
    for(int j=0;j<pSubClass.length();j++,i++)
    {
        lFinal[i]=pSubClass[j];
    }
    lFinal[i++]='\0';
    
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mWMClass,XA_STRING,8,i,lFinal);
}

void write_wm_icon_name(Window pID,const std::string &pIconName,CX11Display *pDisplay)
{
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mWMClass,XA_STRING,pIconName);
}

///////////////////////////
// NET client properties
//

void write_net_wm_desktop(Window pID,unsigned int pDesktop,CX11Display *pDisplay)
{
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetWMDesktop,pDesktop);
}

void write_net_wm_state(Window pID,ENetState pState,CX11Display *pDisplay)
{
    Atom lAtoms[16];
    int lNum=0;

    if(pState&NETSTATE_MODAL)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateModal;
    if(pState&NETSTATE_STICKY)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateSticky;
    if(pState&NETSTATE_MAXHORZ)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateMaxHorz;
    if(pState&NETSTATE_MAXVERT)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateMaxVert;
    if(pState&NETSTATE_SKIPTASKBAR)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateSkipTaskbar;
    if(pState&NETSTATE_SKIPPAGER)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateSkipPager;
    if(pState&NETSTATE_ABOVE)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateAbove;
    if(pState&NETSTATE_BELOW)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateBelow;
    if(pState&NETSTATE_SHADED)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateShaded;
    if(pState&NETSTATE_HIDDEN)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateHidden;
    if(pState&NETSTATE_FULLSCREEN)
        lAtoms[lNum++]=pDisplay->Atoms().mNetWMStateFullScreen;

    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetWMState,XA_ATOM,32,lNum,(unsigned char*)lAtoms);
}

void write_net_wm_icon_geometry(Window pID,const CRect_i &pRect,CX11Display *pDisplay)
{
    int lGeometry[4];
    
    lGeometry[0]=(int)round(pRect.l);
    lGeometry[1]=(int)round(pRect.t);
    lGeometry[2]=(int)round(pRect.w());
    lGeometry[3]=(int)round(pRect.h());
    
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetWMIconGeometry,XA_CARDINAL,32,4,(void*)lGeometry);
}


void write_net_frame_extents(Window pID,const CRect_i &pExtents,CX11Display *pDisplay)
{
    long int lFrame[4];

    lFrame[0]=(int)pExtents.l;
    lFrame[1]=(int)pExtents.r;
    lFrame[2]=(int)pExtents.t;
    lFrame[3]=(int)pExtents.b;

    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetFrameExtents,XA_CARDINAL,32,
                                                 4,(unsigned char*)lFrame);
}

void write_net_wm_visible_name(Window pID,const std::wstring &pVisibleName,CX11Display *pDisplay)
{
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetWMVisibleName,pDisplay->Atoms().mUTF8,pVisibleName);
}

void write_net_wm_sync_request_counter(Window pID,int pCounter,CX11Display *pDisplay)
{
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetWMSyncRequestCounter,pCounter);
}

void write_net_wm_window_type(Window pID,EWindowType pClass,CX11Display *pDisplay)
{
    Atom lAtom;

    switch(pClass)
    {
    case EWindowType::DESKTOP:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeDesktop;
        break;
    case EWindowType::DOCK:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeDock;
        break;
    case EWindowType::TOOLBAR:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeToolbar;
        break;
    case EWindowType::MENU:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeMenu;
        break;
    case EWindowType::UTILITY:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeUtility;
        break;
    case EWindowType::SPLASH:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeSplash;
        break;
    case EWindowType::DIALOG:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeDialog;
        break;
    case EWindowType::DROPDOWNMENU:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeDropdownMenu;
        break;
    case EWindowType::POPUPMENU:
        lAtom=pDisplay->Atoms().mNetWMWindowTypePopupMenu;
        break;
    case EWindowType::TOOLTIP:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeTooltip;
        break;
    case EWindowType::NOTIFICATION:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeNotification;
        break;
    case EWindowType::COMBO:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeCombo;
        break;
    case EWindowType::DND:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeDND;
        break;
    case EWindowType::NORMAL:
    default:
        lAtom=pDisplay->Atoms().mNetWMWindowTypeNormal;
        break;
    }

    pDisplay->SetWindowPropertyAsAtom(pID,pDisplay->Atoms().mNetWMWindowType,lAtom);
}

/////////////////////////
// NET root properties
//

void write_net_supporting_wm_check(Window pID,CX11Display *pDisplay,Window pRootID)
{
    if(pRootID==-1)
        pRootID=pDisplay->GetDefaultRoot();
    
    pDisplay->SetWindowProperty(pRootID,pDisplay->Atoms().mNetSupportingWMCheck,XA_WINDOW,32,1,&pID);
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetSupportingWMCheck,XA_WINDOW,32,1,&pID);
}

void write_net_supported(CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();

    std::vector<Atom> lAtoms;
    
    lAtoms.push_back(pDisplay->Atoms().mNetSupported);
    lAtoms.push_back(pDisplay->Atoms().mNetSupportingWMCheck);
    lAtoms.push_back(pDisplay->Atoms().mNetWMSyncRequest);
    lAtoms.push_back(pDisplay->Atoms().mNetWMSyncRequestCounter);
    lAtoms.push_back(pDisplay->Atoms().mNetClientList);
    lAtoms.push_back(pDisplay->Atoms().mNetClientListStacking);
    lAtoms.push_back(pDisplay->Atoms().mNetNumberOfDesktops);
    lAtoms.push_back(pDisplay->Atoms().mNetDesktopGeometry);
    lAtoms.push_back(pDisplay->Atoms().mNetDesktopViewport);
    lAtoms.push_back(pDisplay->Atoms().mNetCurrentDesktop);
    lAtoms.push_back(pDisplay->Atoms().mNetDesktopNames);
    lAtoms.push_back(pDisplay->Atoms().mNetActiveWindow);
    lAtoms.push_back(pDisplay->Atoms().mNetWorkArea);
    lAtoms.push_back(pDisplay->Atoms().mNetVirtualRoots);
    lAtoms.push_back(pDisplay->Atoms().mNetCloseWindow);
    lAtoms.push_back(pDisplay->Atoms().mNetWMMoveResize);
    lAtoms.push_back(pDisplay->Atoms().mNetWMName);
    lAtoms.push_back(pDisplay->Atoms().mNetWMIconName);
    lAtoms.push_back(pDisplay->Atoms().mNetWMVisibleName);
    lAtoms.push_back(pDisplay->Atoms().mNetWMVisibleIconName);
    lAtoms.push_back(pDisplay->Atoms().mNetWMDesktop);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowType);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeDesktop);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeDock);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeToolbar);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeMenu);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeUtility);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeSplash);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeDialog);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeDropdownMenu);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypePopupMenu);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeTooltip);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeNotification);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeCombo);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeDND);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeNormal);
    lAtoms.push_back(pDisplay->Atoms().mNetWMWindowTypeKDEOverride);
    lAtoms.push_back(pDisplay->Atoms().mNetWMState);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateFullScreen);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateModal);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateSticky);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateMaxVert);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateMaxHorz);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateShaded);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateSkipTaskbar);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateSkipPager);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateAbove);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStateBelow);
    lAtoms.push_back(pDisplay->Atoms().mNetWMStrut);
    lAtoms.push_back(pDisplay->Atoms().mNetWMPID);
    lAtoms.push_back(pDisplay->Atoms().mNetWMIcon);
    lAtoms.push_back(pDisplay->Atoms().mNetWMIconGeometry);
    lAtoms.push_back(pDisplay->Atoms().mNetWMHandledIcons);
    lAtoms.push_back(pDisplay->Atoms().mNetWMPing);
    lAtoms.push_back(pDisplay->Atoms().mBuolaWMExtensions);
    
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetSupported,lAtoms);
}

void write_net_number_of_desktops(int pNumber,CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetNumberOfDesktops,XA_CARDINAL,32,1,&pNumber);
}

void write_net_desktop_geometry(const CSize_i &pSize,CX11Display *pDisplay,Window pID)
{
    if(pID==-1)
        pID=pDisplay->GetDefaultRoot();
    
    int lGeometry[2]={(int)pSize.x,(int)pSize.y};
    pDisplay->SetWindowProperty(pID,pDisplay->Atoms().mNetNumberOfDesktops,XA_CARDINAL,32,2,lGeometry);
}
/*
    ((CX11Window*)GetPhysical())->SetWMProperty(get_default_x11_display()->Atoms().mNetDesktopGeometry,lGeometry,2);
    
    int lViewport[lCount*2];
    int lWorkArea[lCount*4];
    
    for(int i=0;i<lCount;i++)
    {
        lViewport[i*2]=(int)mDesktops.mViewport[i].x;
        lViewport[i*2+1]=(int)mDesktops.mViewport[i].x;
        lWorkArea[i*4]=(int)mDesktops.mWorkArea[i].l;
        lWorkArea[i*4+1]=(int)mDesktops.mWorkArea[i].t;
        lWorkArea[i*4+2]=(int)mDesktops.mWorkArea[i].w();
        lWorkArea[i*4+3]=(int)mDesktops.mWorkArea[i].h();
    }
    
    ((CX11Window*)GetPhysical())->SetWMProperty(get_default_x11_display()->Atoms().mNetDesktopViewport,lViewport,2*lCount);
    ((CX11Window*)GetPhysical())->SetWMProperty(get_default_x11_display()->Atoms().mNetWorkArea,lWorkArea,4*lCount);
}
*/


/*namespace icccm */ } /*namespace x11*/ } /*namespace gui*/ } /*namespace buola*/ }
